package server;

import java.util.ArrayList;

import server.util.*;
import server.model.players.*;
import server.model.players.packets.Command;
import server.model.npcs.*;
import server.world.*;
public class Server implements Runnable {
	
	//public static commands list here 
	public static String commandsDirectory = "";
	public static ArrayList<Processer> processLists = new ArrayList<Processer>();
	public static String configDirectory = "";
	public static String bansDirectory = "";
	public static boolean canRun = false;
	public static void addProcesser(Processer p) {
		if (p == null) return;
		if(!processLists.contains(p))
			processLists.add(p);
	}

	public static void main(java.lang.String args[]) {
		
		commandsDirectory = args[0];
		configDirectory  = args[1];
		System.out.println("Config Directory: " + configDirectory);
		bansDirectory = args[2];
		Command.loadCommands();
		canRun = true;
		clientHandler = new Server();
		itemHandler = new ItemHandler();
		playerHandler = new PlayerHandler();
		npcHandler = new NPCHandler();
		shopHandler = new ShopHandler();
		objectHandler = new ObjectHandler();
		ConnectionHandler.initialize();
		(new Thread(clientHandler)).start();			
		long lastTicks = System.currentTimeMillis();
		long totalTimeSpentProcessing = 0;
		int cycle = 0;
		while(!shutdownServer) {
			for(Processer p : processLists) {
				if(p == null) continue;
					if(!p.running) {
						p.running = true;
						Thread x = new Thread(p);
						//System.out.println("Created new thread for: " + p.getClass().getName() + ", thread name is: " + x.getName());
						x.start();
					}
			}
			//If its commented out, then its running on its own thread using superclass Processer
			//itemHandler.process();
			//playerHandler.process();	
            //npcHandler.process();
			//shopHandler.process();
			//objectHandler.process();
			
			long timeSpent = System.currentTimeMillis()-lastTicks;
			totalTimeSpentProcessing += timeSpent;
			if(timeSpent >= Config.CYCLE_TIME) {
				timeSpent = Config.CYCLE_TIME;
			}

			try { 
				Thread.sleep(Config.CYCLE_TIME-timeSpent); 
				} catch(java.lang.Exception _ex) { 
					_ex.printStackTrace();
				}
			lastTicks = System.currentTimeMillis();
			cycle ++;
		}

		
		playerHandler.destruct();
		clientHandler.killServer();
		clientHandler = null;
	
	}

	public static Server clientHandler = null;			
	public static java.net.ServerSocket clientListener = null;
	public static boolean shutdownServer = false;		
	public static boolean shutdownClientHandler;			
	public static int ServerlistenerPort = 43594; 
	public static ItemHandler itemHandler;
	public static PlayerHandler playerHandler;
    public static NPCHandler npcHandler;
	public static ShopHandler shopHandler;
	public static ObjectHandler objectHandler;

	public void run() {
		while(!canRun) {
			
		}
		try {
			shutdownClientHandler = false;
			clientListener = new java.net.ServerSocket(ServerlistenerPort, 1, null);
			Misc.println("Starting "+Config.SERVER_NAME+" on " + clientListener.getInetAddress().getHostAddress() + ":" + clientListener.getLocalPort());
			while(true) {
				java.net.Socket s = clientListener.accept();
				s.setTcpNoDelay(true);
				String connectingHost = s.getInetAddress().getHostName();
				if(!ConnectionHandler.floodProtection(connectingHost) && !ConnectionHandler.containsIp(connectingHost) && !ConnectionHandler.isIpBanned(connectingHost)) {
					ConnectionHandler.addIp(connectingHost);
					Misc.println("ClientHandler: Accepted from "+connectingHost+":"+s.getPort());
					playerHandler.newPlayerClient(s, connectingHost);
				} else {
					Misc.println("ClientHandler: Rejected "+connectingHost+":"+s.getPort());
					s.close();
				}
			}
		} catch(java.io.IOException ioe) {
			if(!shutdownClientHandler)
				Misc.println("Error: Unable to startup listener on "+ServerlistenerPort+" - port already in use?");
			else Misc.println("ClientHandler was shut down.");
		}
	}

	public void killServer() {
		try {
			shutdownClientHandler = true;
			if(clientListener != null) clientListener.close();
			clientListener = null;
		} catch(java.lang.Exception __ex) {
			__ex.printStackTrace();
		}
	}
		
}
